package Tools;

import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECPoint;
import java.security.spec.EllipticCurve;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.UUID;

import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA512Digest;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import model.ASserver;
import model.EC;
import model.PSK;
import model.Point;


public class UtilFactory {
	
	//xml对象的保存路径
	static String path="D://TEAM//ObjectXml/";
	
	//将经过SHA算法进行加密后的字节数组转换成16进制字符串
	public static String convertByteToHexString(byte [] bytes){
		if (bytes==null||bytes.length<1)
			throw new IllegalArgumentException("this bytearray can't be null or empty"); 
		StringBuilder res=new StringBuilder();
		int len=bytes.length;
		for (int i=0;i<len;i++){
			if ((bytes[i]&0xff)<0x10)
				res.append("0");
			res.append(Integer.toHexString(0xff&bytes[i]));
		}
		return res.toString().toLowerCase();
	}
	
	/**
	 *对信息进行SHA-520加密
	 * @param message 带加密的信息
	 * @return 加密过后的信息
	 */
	public static String SHA512(String message){
		Digest bcSHA512=new SHA512Digest();
		byte[] bytes=message.getBytes();
		int len=bytes.length;
		bcSHA512.update(bytes, 0, len);
		byte[] bytefinal=new byte[bcSHA512.getDigestSize()];
		bcSHA512.doFinal(bytefinal, 0);
		return convertByteToHexString(bytefinal);
	}
	
	//用于生成各种唯独的id
	public static String generateUUID(){
		UUID gUUid =UUID.randomUUID();
		String uudi = gUUid.toString();
		return uudi.replaceAll("-", "");
	}
	
	/**
	 * AS服务商公钥私钥对初始化，初始化成功，返回AS服务商的ID
	 * @return
	 */
	public static String ECinit(ASserver as){
		String ASID="null";
		EC ec=new EC();
		ec.a=(Integer.parseInt(as.getEca()));
		ec.b=(Integer.parseInt(as.getEcb()));
		ec.p=(Integer.parseInt(as.getEcp()));
		ec.xq=(Integer.parseInt(as.getEcpx()));
		ec.yq=(Integer.parseInt(as.getEcpy()));
		Point p=new Point(as.getEcpx(),as.getEcpy());
		Point pubkey=ec.dianchen(Integer.parseInt(as.getPrivatekey()), p);
		as.setPubkeyx(pubkey.getX());
		as.setPublickeyy(pubkey.getY());
		//获得到椭圆曲线的各个参数和生成的秘钥对之后，将as信息用xml文件保存下来，文件名字为AS服务商的ID
		String aspath=path+as.getAsid()+".xml";
		try {
			UtilFactory.objectXmlEncoder(as, aspath);
			ASID=as.getAsid();
		} catch (Exception e) {
			System.out.println("AS初始化异常");
		}
		return ASID;
	}
	/**
	 * 初始化psk集合
	 * @return 状态值，1表示集合生成成功，0表示集合生成失败
	 */
	public static int initPsk(int len){
		int result=0;
		Random ran=new Random();
		int nonce=ran.nextInt(1000);
		String hashres=""+nonce;
		List<PSK> psks=new ArrayList<>();
		for (int i=0;i<len;i++){
			hashres=SHA512(hashres);
			PSK psk=new PSK();
			psk.setPsk(hashres);
			psk.setValiedtime(""+(i+1));
			psks.add(psk);
		}
		String pskpath=path+"psks.xml";
		try {
			UtilFactory.objectXmlEncoder(psks, pskpath);
			result=1;
		} catch (Exception e) {
			System.out.println("PSK初始化失败:"+e.getMessage());
		}
		return result;
	}
	
	/**
	 * 将两个16进制字符串进行异或
	 * @param str1
	 * @param str2
	 * @return 结果的16进制字符串
	 */
	public static String HexXor(String str1,String str2){
		int len1=str1.length();
		int len2=str2.length();
		int sub=len1>=len2?len1-len2:len2-len1;
		int len=len1>=len2?len1:len2;
		String lonstr="null";
		String shstr="null";
		if (len1>=len2){
			lonstr=str1;
			shstr=str2;
		}else {
			lonstr=str2;
			shstr=str1;
		}
		StringBuilder builder=new StringBuilder();
		//两个字符串不重叠部分和字符0异或还是本身，直接保存下来
		if (sub!=0)
		builder.append(lonstr.substring(0,sub));
		String newstr=lonstr.substring(sub,len);
		double commonlen=newstr.length();
		//将16进制字符串划成8个一组，进行转换成BigInteger,然后再进行异或运算
		int count=(int) Math.ceil(commonlen/8);//向上取整
		for (int i=0;i<count;i++){
			int lastlen=0;
			String xorstr="";
			BigInteger big1,big2;
			if ((i+1)*8>commonlen){
				big1=new BigInteger(newstr.substring(8*i, (int)commonlen),16);
				big2=new BigInteger(shstr.substring(8*i,  (int)commonlen),16);
				lastlen=(int)commonlen-8*i;
				xorstr=convertByteToHexString(big1.xor(big2).toByteArray());
				int xorlen=xorstr.length();
				if (xorlen<lastlen){
					for (int k=0;k<lastlen-xorlen;k++){
						builder.append("0");
					}
					builder.append(xorstr.substring(0,xorlen));
				}
				else{
				builder.append(xorstr.substring(xorlen-lastlen,xorlen));
				}
			}
			else{
				big1=new BigInteger(newstr.substring(8*i,8*(1+i)),16);
				big2=new BigInteger(shstr.substring(8*i,8*(1+i)),16);
				xorstr=convertByteToHexString(big1.xor(big2).toByteArray());
				if (xorstr.length()>=8){
					//说明自动在16进制结果串去那面填补了0
					xorstr=xorstr.substring(xorstr.length()-8,xorstr.length());
				}
				else{
					//说明自动去掉了16进制结果串前面的0
					for(int m=0;m<8-xorstr.length();m++)
						builder.append("0");
				}
				builder.append(xorstr);
			}
		}		
		
		return builder.toString();
	}
	
	//使用xml文件实现数据的持久化
	/** 
	 * 注意：只能将java对象的私有String属性数据转换成xml文件中的节点进行存储
	  * 把java的可序列化的对象(实现Serializable接口)序列化保存到XML文件里面,如果想一次保存多个可序列化对象请用集合进行封装 
	  * 保存时将会用现在的对象原来的XML文件内容 
	  * @param obj 要序列化的可序列化的对象 
	  * @param fileName 带完全的保存路径的文件名  
	  * @throws FileNotFoundException 指定位置的文件不存在 
	  * @throws IOException 输出时发生异常 
	  * @throws Exception 其他运行时异常 
	  */ 
	public static void objectXmlEncoder(Object obj,String fileName) 
			  throws FileNotFoundException,IOException,Exception 
			 {   
			  //创建输出文件 
			  File fo = new File(fileName); 
			  //文件不存在,就创建该文件 
			  if(!fo.exists()) 
			  { 
			   //先创建文件的目录
			      String path = fileName.substring(0,fileName.lastIndexOf('/')); 
			      File pFile = new File(path); 
			      pFile.mkdirs();          
			  } 
			  //创建文件输出流 
			  FileOutputStream fos = new FileOutputStream(fo); 
			  //创建XML文件对象输出类实例 
			  XMLEncoder encoder = new XMLEncoder(fos);   
			  //对象序列化输出到XML文件 
			  encoder.writeObject(obj); 
			  encoder.flush();  
			  //关闭序列化工具 
			  encoder.close(); 
			  //关闭输出流 
			  fos.close();     
			 }  
	
	 /** 
	  * 读取由objSource指定的XML文件中的序列化保存的对象,返回的结果经过了List封装 
	  * @param objSource 带全部文件路径的文件全名 
	  * @return 由XML文件里面保存的对象构成的List列表(可能是一个或者多个的序列化保存的对象)   
	  * @throws FileNotFoundException 指定的对象读取资源不存在 
	  * @throws IOException 读取发生错误 
	  * @throws Exception 其他运行时异常发生 
	  */ 
	 public static List objectXmlDecoder(String objSource)  
	  throws FileNotFoundException,IOException,Exception 
	 { 
	  List objList = new ArrayList();     
	  File fin = new File(objSource); 
	  FileInputStream fis = new FileInputStream(fin); 
	  XMLDecoder decoder = new XMLDecoder(fis); 
	  Object obj = null; 
	  try 
	  { 
	   while( (obj = decoder.readObject()) != null) 
	   { 
	    objList.add(obj); 
	   } 
	  } 
	  catch (Exception e) 
	  { 
	  } 
	  fis.close(); 
	  decoder.close();      
	  return objList; 
	 } 
}
